<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
		*{margin:0;padding:0;}
		body{
			color:#333;
			font-size: 14px;
		}
		li{list-style:none;}
		#game{
			width: 1000px;	
			height: 1000px;	
			margin:100px auto;
			border:2px solid #e3e3e3;
			position:relative;	
		}
		#game span{
			display: block;	
			width:20px;
			height:20px;
			background-color:#f99;
			position:absolute;
		}
		#food{
			position:absolute;
			left:0;
			top:0;
			width: 20px;
			height: 20px;
			background-color:orange;
			border-radius: 50%;
		}
		#status{
			width:300px;
			padding:20px 10px;
			border:1px solid #e3e3e3;
			position:absolute;
			left:100px;
		}
		#status li{
			line-height:32px;
		}
		#score{
			color:#f00;
			font-family:"Arial";
			font-size: 24px;
		}
		#startGame{
			display: inline-block;
			padding: 6px 12px;
			margin-bottom: 0;
			font-size: 14px;
			font-weight: 400;
			line-height: 1.42857143;
			text-align: center;
			white-space: nowrap;
			vertical-align: middle;
			touch-action: manipulation;
			cursor: pointer;
			user-select: none;
			background-image: none;
			border: 1px solid transparent;
			border-radius: 4px;
		    color: #fff;
		    background-color: #337ab7;
		    border-color: #2e6da4;
		}
	</style>
</head>
<body>
	<audio id="deadVioce">
		<source src="dead.ogv" type="audio/mpeg" />
	</audio>

	<ul id="status">
		<li>now Player： <span>玩家1</span></li>
		<li>score：<span id="score">0</span></li>
		<li>
			难度：
			<select name="" id="hardModel">
				<option value="110">简单</option>
				<option value="70" selected>普通</option>
				<option value="50">困难</option>
				<option value="40">大师</option>
				<option value="30">地狱</option>
			</select>
		</li>
		<li>
			<button id="startGame">开始游戏</button>
		</li>
	</ul>
	<div id="game">
		<div id="food"></div>
	</div>
	<script src="machine.js"></script>
	<script>
		// 蛇
		var snake = {
			length:5,//蛇身的长度
			width:20, //蛇的宽度
			body:[],  // 记录身体的数据，存放所有关于蛇身体的Node节点
			move:function(){
				// 在游戏视图上把蛇往右移动一步
				var foot = this.body[0]		//蛇尾的Node节点
				var head = this.body[this.body.length - 1]		// 蛇头的Node节点

				if(game.dir == "right"){
					//往右移动一步
					foot.style.left = parseInt(head.style.left) + this.width + "px";
					foot.style.top = head.style.top;
				}
				if(game.dir == "bottom"){
					foot.style.left = head.style.left;
					foot.style.top = parseInt(head.style.top) + this.width + "px";
				}
				if(game.dir == "top"){
					foot.style.left = head.style.left;
					foot.style.top = parseInt(head.style.top) - this.width + "px";
				}
				if(game.dir == "left"){
					foot.style.left = parseInt(head.style.left) - this.width + "px";
					foot.style.top = head.style.top;
				}

				// 调整记录蛇身体的数组之间顺序关系
				var tem = this.body[0];
				this.body.shift()
				this.body.push(tem)

				// 当前移动后的蛇头
				var HEAD = this.body[this.body.length - 1];

				// 上帝模式
				if(game.godModel){
					// 当前蛇头
					var head = {
						x:parseInt(HEAD.style.left),
						y:parseInt(HEAD.style.top)
					}
					// 当前食物
					var fd = {
						x:parseInt(food.pointX),
						y:parseInt(food.pointY)
					}
					// 先调整X轴
					if(head.x !== fd.x){

						// 食物在右
						if(head.x < fd.x){
							// 当前行进方向不为左的情况，超目标方向走
							if(game.dir !== "left"){
								game.dir = "right"
							}
							// 当进行反向需要二次转向的时候(上优先)
							else{

								// 上方有墙吗
								if(head.y == 0){
									game.dir = "bottom"
								}
								// 上方没墙
								else{
									// 暂且认为上方是安全
									var istopSafe = true;

									
									for(var i = 0; i < this.body.length - 1;i++){
										if(head.y ==  parseInt(this.body[i].style.top) + this.width){
											// 上方虽然没墙但是有身体
											istopSafe = false;
										}
									}

									// 上方既没有墙也没有身体
									if(istopSafe){
										game.dir = "top"
									}
									// 上方有身体
									else{
										game.dir = "bottom"
									}
								}
							}
						}
						// 食物在左
						if(head.x > fd.x){
							// 当前行进方向不为左的情况，超目标方向走
							if(game.dir !== "right"){
								game.dir = "left"
							}
							// 当进行反向需要二次转向的时候(上优先)
							else{

								// 上方有墙吗
								if(head.y == 0){
									game.dir = "bottom"
								}
								// 上方没墙
								else{
									// 暂且认为上方是安全
									var istopSafe = true;

									
									for(var i = 0; i < this.body.length - 1;i++){
										if(head.y ==  parseInt(this.body[i].style.top) + this.width){
											// 上方虽然没墙但是有身体
											istopSafe = false;
										}
									}

									// 上方既没有墙也没有身体
									if(istopSafe){
										game.dir = "top"
									}
									// 上方有身体
									else{
										game.dir = "bottom"
									}
								}
							}
						}
					}
					// 再调整Y轴
					else{
						// 食物在下
						if(head.y < fd.y){
							// 当前行进方向不为上的情况，超目标方向走
							if(game.dir !== "top"){
								game.dir = "bottom"
							}
							// 当进行反向需要二次转向的时候(左优先)
							else{

								// 左方有墙吗
								if(head.x == 0){
									game.dir = "right"
								}
								// 左方没墙
								else{
									// 暂且认为左方是安全
									var istopSafe = true;

									
									for(var i = 0; i < this.body.length - 1;i++){
										if(head.x ==  parseInt(this.body[i].style.top) - this.width){
											// 左方虽然没墙但是有身体
											istopSafe = false;
										}
									}

									// 左方既没有墙也没有身体
									if(istopSafe){
										game.dir = "left"
									}
									// 左方有身体
									else{
										game.dir = "right"
									}
								}
							}
						}
						// 食物在上
						if(head.y > fd.y){
							// 当前行进方向不为下的情况，超目标方向走
							if(game.dir !== "bottom"){
								game.dir = "top"
							}
							// 当进行反向需要二次转向的时候(左优先)
							else{
								// 左方有墙吗
								if(head.x == 0){
									game.dir = "right"
								}
								// 左方没墙
								else{
									// 暂且认为左方是安全
									var istopSafe = true;

									
									for(var i = 0; i < this.body.length - 1;i++){
										if(head.x ==  parseInt(this.body[i].style.top) - this.width){
											// 左方虽然没墙但是有身体
											istopSafe = false;
										}
									}

									// 左方既没有墙也没有身体
									if(istopSafe){
										game.dir = "left"
									}
									// 左方有身体
									else{
										game.dir = "right"
									}
								}
							}
						}
					}

				}

				// 死亡碰撞检测(碰撞墙壁)
				if(parseInt(HEAD.style.left) >= 1000 || parseInt(HEAD.style.left) < 0 || parseInt(HEAD.style.top) < 0 || parseInt(HEAD.style.top) >= 1000){
					game.dead();
				}

				// 碰到自身的死亡碰撞检测
				for(var i = 0; i < this.body.length - 1;i++){
					if(HEAD.style.top === this.body[i].style.top && HEAD.style.left === this.body[i].style.left){
						game.dead();
					}
				}

				// 得分碰撞检测
				if(parseInt(HEAD.style.left) === food.pointX && parseInt(HEAD.style.top) === food.pointY){
					game.getScore()
				}
			},
			// 增加一节身体
			addBody:function(){
				// 创建一个节点
				var span = document.createElement("span");
				// 给该节身体赋值一个随机颜色
				span.style.backgroundColor = getRandomColor();
				// 把当前蛇尾的坐标赋值给了新的身体上
				span.style.left = this.body[0].style.left;
				span.style.top = this.body[0].style.top;
				// 将新生成的身体插入到数组的最前面
				this.body.unshift(span);
				// 更新游戏界面
				game.node.appendChild(span)
			}
		}

		// 游戏
		var game = {
			node:$("#game"),	//游戏画布的Node节点
			scoreNode:$("#score"),  //分值的Node节点
			startNode:$("#startGame"), //开始游戏按钮的Node节点
			deadVioceNode:$("#deadVioce"),
			hardModelNode:$("#hardModel"),
			dir:"right", 		//当前游戏中蛇移动的方向
			godModel:false,		//上帝模式开关
			width:1000,			//游戏宽度
			status:false,			//当前游戏状态，true为游戏正在进行，false为游戏停止
			score:0,
			hardModel:100,         //游戏难度,数字越小则游戏越难

			init:function(){
				this.dir = "right"
				// 清空游戏场景中遗留下来的蛇的身体
				for(var i = 0; i < snake.body.length;i++){
					this.node.removeChild(snake.body[i])
				}
				snake.body = [];

				// 清空分数
				this.score = 0;
				this.scoreNode.innerHTML = this.score;

				// 初始化一条蛇
				for(var i = 0; i < snake.length;i++){
					// 生成一节身体
					var span = document.createElement("span");
					span.style.top = "0px";
					span.style.left = snake.width * i + "px";

					// 获取一个随机颜色赋值给该节身体上
					span.style.backgroundColor = getRandomColor()

					// 把新生成的蛇身体记录到body数组中
					snake.body.push(span)

					// 把这节身体插入到游戏画布中
					this.node.appendChild(span)
				}

				// 随机生成一个食物
				food.createFood();

				// 修正游戏进行状态
				this.status = true;

				// 调整按钮可点击状态
				this.startNode.disabled = true;

				// 修正游戏难度
				this.hardModel = this.hardModelNode.value; 
			},
			// 开始游戏
			start:function(){
				// 初始化整盘游戏
				this.init();

				// 开始移动
				play = setInterval(function(){
					snake.move()
				},this.hardModel)

				// 停止死亡音乐（如果还在播的话）
				this.deadVioceNode.pause();
			},
			// 死亡
			dead:function(){
				clearInterval(play)
				// 修正游戏进行状态
				this.status = false;
				// 调整按钮可点击状态
				this.startNode.disabled = false;
				// 播放死亡音乐
				this.deadVioceNode.play();
			},

			// 得分 
			getScore:function(){
				// 重新生成一个食物
				food.createFood()
				// 给蛇增加一节身体
				snake.addBody()

				this.score = this.score + 10;
				this.updataScore();
			},
			// 更新得分
			updataScore:function(){
				this.scoreNode.innerHTML = this.score;
				this.scoreNode.style.opacity = 0;

				var t = setInterval(function(){
					var o = Number(this.scoreNode.style.opacity);
					if(o < 1){
						this.scoreNode.style.opacity = o + 0.02;
					}
					else{
						clearInterval(t)
					}
				},16)
			}
		}
		
		// 食物
		var food = {
			node:$("#food"),	// 食物的Node节点
			pointX:0,			// 食物坐标
			pointY:0,	
			createFood:function(){
				// 0-980 之间的 20的整数倍
				this.pointX = Math.round(Math.random() * (game.width / snake.width - 1)) *snake.width;
				this.pointY = Math.round(Math.random() * (game.width / snake.width - 1)) *snake.width;

				// 调整游戏场景中食物的坐标值
				this.node.style.left = this.pointX + "px";
				this.node.style.top = this.pointY + "px";
			}
		}



		

		game.startNode.onclick = function(){
			// 开始游戏
			game.start();
		}

		
		// 键盘操控蛇的移动方向
		window.onkeydown = function(e){
			if(e.keyCode === 37 && game.dir!== "right"){
				game.dir = "left";
			}
			if(e.keyCode === 38 && game.dir!== "bottom"){
				game.dir = "top";
			}
			if(e.keyCode === 39 && game.dir!== "left"){
				game.dir = "right";
			}
			if(e.keyCode === 40 && game.dir!== "top"){
				game.dir = "bottom";
			}
		}
	</script>
</body>
</html>